module Transform

using StaticArrays
using Lazy

import ..Model
const XY = Model.XY

export TransformMatrix, identity_transform, scale, translate, transform, undo

import LinearAlgebra
const LA = LinearAlgebra

const TransformMatrix = SMatrix{3,3,Float64}

function gen_identity_matrix() :: TransformMatrix
  n = 3
  @> begin
    fill(1.0, (n, n))
    LA.Diagonal
    Array
    SMatrix{n,n}
  end
end

const identity_transform = gen_identity_matrix()

function scale(m :: TransformMatrix, x, y) :: TransformMatrix
  TransformMatrix([x 0 0; 0 y 0; 0 0 1]) * m
end

function translate(m :: TransformMatrix, x, y) :: TransformMatrix
  TransformMatrix([1 0 x; 0 1 y; 0 0 1]) * m
end

function remove_translation(m :: TransformMatrix) :: TransformMatrix
  @> begin
    m
    copy
    *(@SMatrix [1 0 0; 0 1 0; 0 0 0])
    +(@SMatrix [0 0 0; 0 0 0; 0 0 1])
  end
end

function transform(m :: TransformMatrix, x, y) :: XY
  xyz = [x, y, 1]
  transfed = m * xyz
  x = transfed[1]
  y = transfed[2]
  XY(x, y)
end

function transform(m :: TransformMatrix, xy :: XY)
  transform(m, xy[1], xy[2])
end

const invert = StaticArrays.inv

function undo(m, x, y)
  transform(invert(m), x, y)
end

function undo(m, xy :: XY)
  transform(invert(m), xy)
end

function undo_scale(m, xy :: XY)
  @> m remove_translation undo(xy)
end

end
